﻿using System;
using System.Data;
using System.Data.Common;

namespace Flagwind.Data
{
	/// <summary>
	/// 公共数据访问基础类
	/// <remarks>
	/// 正常情况下CRUD方法都是使用一个局部的连接变量，因此是线程安全的原子操作，
	/// 如果开启了事务，或者开启了 opensession，将共享同一个连接对象，直到事务结束或者关闭会话，因此此时连接对象不是线程安全的。
	/// </remarks>
	/// </summary>
	public abstract class DataProviderBase : IDataProvider
	{
		#region 私有字段

		private IDbConnection _connection;
		private string _connectionString;
		private bool _disposed;
		private string _errorMessage = string.Empty;
		private bool _onErrorRollback = true;
		private bool _onErrorThrow = true;
		private string _selectIdentityText;
		private IDbConnection _sessionConnection;
		private bool _sqlServerCompatible = true;
		private int _transCount; //事务计数器
		private IDbTransaction _transation; // 会话使用的连接
		private string _writeConnectionString;

		#endregion

		#region 公共属性

		public string Name
		{
			get;
			set;
		}

		/// <summary>
		/// 获取连接字符串构造类。
		/// </summary>
		public abstract DbConnectionStringBuilder ConnectionStringBuilder
		{
			get;
		}

		/// <summary>
		/// 获取连接数据库用户的Id。
		/// </summary>
		public abstract string ConnectionUserId
		{
			get;
		}

		/// <summary>
		/// 数据操作的错误信息，请在每次查询后检查该信息。
		/// </summary>
		public string ErrorMessage
		{
			get
			{
				return _errorMessage;
			}
			protected set
			{
				if(!string.IsNullOrEmpty(value))
				{
					_errorMessage += ";" + value;
				}
				else
				{
					_errorMessage = value;
				}
			}
		}

		/// <summary>
		/// 在事务执行期间，更新过程如果出现错误，是否自动回滚事务。默认为是。
		/// </summary>
		public bool OnErrorRollback
		{
			get
			{
				return _onErrorRollback;
			}
			set
			{
				_onErrorRollback = value;
			}
		}

		/// <summary>
		/// 查询出现错误是否是将错误抛出。默认为是。
		/// 如果设置为否，将简化调用程序的异常处理，但是请检查每次更新后受影响的结果数和错误信息来决定你的程序逻辑。
		/// 如果在事务执行期间，期望出现错误后立刻结束处理，请设置本属性为 是。
		/// </summary>
		public bool OnErrorThrow
		{
			get
			{
				return _onErrorThrow;
			}
			set
			{
				_onErrorThrow = value;
			}
		}

		/// <summary>
		/// 获取或者设置事务对象
		/// </summary>
		public IDbTransaction Transaction
		{
			get
			{
				return _transation;
			}
			set
			{
				_transation = value;
			}
		}

		/// <summary>
		/// SQL SERVER 兼容性设置，默认为兼容。该特性可以将SQLSERVER的语句移植到其它其它类型的数据库，例如字段分隔符号，日期函数等。
		/// 如果是拼接字符串方式的查询，建议设置为False，避免在拼接ＳＱＬ的时候过滤掉'@'等特殊字符
		/// </summary>
		public bool SqlServerCompatible
		{
			get
			{
				return _sqlServerCompatible;
			}
			set
			{
				_sqlServerCompatible = value;
			}
		}

		/// <summary>
		/// 当前数据库的类型枚举。
		/// </summary>
		public abstract DataProviderType ProviderType
		{
			get;
		}

		/// <summary>
		/// 获取参数名的标识字符。
		/// </summary>
		public virtual string ParameterChar
		{
			get
			{
				return "@";
			}
		}

		/// <summary>
		/// 获取执行 SQL 查询的超时时间，单位：秒。
		/// </summary>
		public int CommandTimeOut
		{
			get;
			protected set;
		}

		/// <summary>
		/// 在插入具有自增列的数据后，获取刚才自增列的数据的方式。
		/// 默认使用 @@IDENTITY，在其它具体数据库实现类可能需要重写该属性或者运行时动态指定。
		/// </summary>
		public virtual string SelectIdentityText
		{
			get
			{
				if(string.IsNullOrWhiteSpace(this._selectIdentityText))
				{
					return "SELECT @@IDENTITY";
				}
				return _selectIdentityText;
			}
			set
			{
				_selectIdentityText = value;
			}
		}

		/// <summary>
		/// 获取最近一次执行查询的所耗费的时间，单位：毫秒。
		/// </summary>
		public long LastElapsedTime
		{
			get;
			protected set;
		}

		/// <summary>
		/// 数据连结字符串。
		/// </summary>
		public string ConnectionString
		{
			get
			{
				return _connectionString;
			}
			set
			{
				_connectionString = Utility.ReplaceWebRootPath(value);
			}
		}

		/// <summary>
		/// 写入数据的连接字符串，ExecuteNoneQuery 方法将自动使用该连接。
		/// </summary>
		public string DataWriteConnectionString
		{
			get
			{
				return _writeConnectionString ?? this.ConnectionString;
			}
			set
			{
				_writeConnectionString = value;
			}
		}

		#endregion

		#region 获取方法

		#region GetParameter

		/// <summary>
		/// 获取一个新参数对象。
		/// </summary>
		/// <returns>特定于数据源的参数对象。</returns>
		public abstract IDataParameter GetParameter();

		/// <summary>
		/// 获取一个新参数对象。
		/// </summary>
		/// <param name="name">参数名字。</param>
		/// <param name="type">数据库数据类型。</param>
		/// <param name="size">字段大小。</param>
		/// <returns>特定于数据源的参数对象。</returns>
		public abstract IDataParameter GetParameter(string name, DbType type, int size);

		/// <summary>
		/// 获取一个新参数对象。
		/// </summary>
		/// <param name="name">参数名字。</param>
		/// <param name="type">>数据库数据类型。</param>
		/// <returns>特定于数据源的参数对象。</returns>
		public virtual IDataParameter GetParameter(string name, DbType type)
		{
			var parameter = this.GetParameter();
			parameter.ParameterName = name;
			parameter.DbType = type;
			return parameter;
		}

		/// <summary>
		/// 根据参数名和值返回参数一个新的参数对象。
		/// </summary>
		/// <param name="name">参数名。</param>
		/// <param name="value">参数值。</param>
		/// <returns>特定于数据源的参数对象。</returns>
		public virtual IDataParameter GetParameter(string name, object value)
		{
			var parameter = this.GetParameter();
			parameter.ParameterName = name;
			parameter.Value = value;
			return parameter;
		}

		/// <summary>
		/// 获取一个新参数对象。
		/// </summary>
		/// <param name="name">参数名。</param>
		/// <param name="type">参数值。</param>
		/// <param name="size">参数大小。</param>
		/// <param name="direction">参数输出类型。</param>
		/// <returns>特定于数据源的参数对象。</returns>
		public IDataParameter GetParameter(string name, DbType type, int size, ParameterDirection direction)
		{
			var parameter = this.GetParameter(name, type, size);
			parameter.Direction = direction;
			return parameter;
		}

		/// <summary>
		/// 获取一个新参数对象。
		/// </summary>
		/// <param name="name">参数名。</param>
		/// <param name="type">参数类型。</param>
		/// <param name="size">参数值的长度。</param>
		/// <param name="direction">参数的输入输出类型。</param>
		/// <param name="precision">参数值参数的精度。</param>
		/// <param name="scale">参数的小数位位数。</param>
		/// <returns>特定于数据源的参数对象。</returns>
		public IDataParameter GetParameter(string name, DbType type, int size, ParameterDirection direction, byte precision, byte scale)
		{
			var parameter = (IDbDataParameter)this.GetParameter(name, type, size);
			parameter.Direction = direction;
			parameter.Precision = precision;
			parameter.Scale = scale;
			return parameter;
		}

		#endregion

		#region GetSchema

		/// <summary>
		/// 返回此 SqlConnection 的数据源的架构信息。
		/// </summary>
		/// <param name="collectionName">集合名称，可以为空</param>
		/// <param name="restrictionValues">请求的架构的一组限制值，可以为空</param>
		/// <returns>数据库架构信息表</returns>
		public abstract DataTable GetSchema(string collectionName, string[] restrictionValues);

		#endregion

		#region GetConnection

		/// <summary>
		/// 获取数据库连接对象实例。
		/// </summary>
		/// <returns>数据库连接对象。</returns>
		public IDbConnection GetConnection()
		{
			// 优先使用事务的连接
			if(this.Transaction != null)
			{
				var transaction = this.Transaction;
				if(transaction.Connection != null)
				{
					return transaction.Connection;
				}
			}
			// 如果开启连接会话，则使用该连接
			if(this._sessionConnection != null)
			{
				return this._sessionConnection;
			}
			return this.GetConnection(this.ConnectionString);
		}

		/// <summary>
		/// 获取数据库连接对象实例。
		/// </summary>
		/// <param name="connectionString">连接字符串。</param>
		/// <returns>数据库连接对象</returns>
		public abstract IDbConnection GetConnection(string connectionString);

		#endregion

		/// <summary>
		/// 获取存储过程、函数的定义内容，如果子类支持，需要在子类中重写。
		/// </summary>
		/// <param name="name">存储过程名称。</param>
		/// <returns>定义内容。</returns>
		public virtual string GetProcDetail(string name)
		{
			return "";
		}

		/// <summary>
		/// 获取视图定义，如果子类支持，需要在子类中重写
		/// </summary>
		/// <param name="name">视图名称</param>
		/// <returns></returns>
		public virtual string GetViewDetail(string name)
		{
			return "";
		}

		#endregion

		#region 执行方法

		#region ExecuteNonQuery

		/// <summary>
		/// 执行不返回值的查询，如果此查询出现了错误并且设置 OnErrorThrow 属性为 是，将抛出错误；否则将返回 -1，此时请检查ErrorMessage属性；
		/// 如果此查询在事务中并且出现了错误，将根据 OnErrorRollback 属性设置是否自动回滚事务。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>受影响的行数。</returns>
		public int ExecuteNonQuery(string sql)
		{
			return this.ExecuteNonQuery(sql, CommandType.Text, null);
		}

		/// <summary>
		/// 执行不返回值的查询，如果此查询出现了错误并且设置 OnErrorThrow 属性为 是，将抛出错误；否则将返回 -1，此时请检查ErrorMessage属性；
		/// 如果此查询在事务中并且出现了错误，将根据 OnErrorRollback 属性设置是否自动回滚事务。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>受影响的行数。</returns>
		public virtual int ExecuteNonQuery(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			this.ErrorMessage = "";
			var connection = this.GetConnection();
			// 连接已经打开，不能切换连接字符串
			if(connection.State != ConnectionState.Open)
			{
				connection.ConnectionString = this.DataWriteConnectionString;
			}
			var command = connection.CreateCommand();
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			var logger = new Logger(true);
			int result = -1;
			try
			{
				//如果开启事务，则由上层调用者决定何时提交事务。
				result = command.ExecuteNonQuery();
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				//如果开启事务，那么此处应该回退事务
				if(command.Transaction != null && OnErrorRollback)
				{
					command.Transaction.Rollback();
				}
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(this.OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				long lastElapsedTime;
				logger.Log(command, "Flagwind.Data", out lastElapsedTime);
				this.LastElapsedTime = lastElapsedTime;
				this.CloseConnection(connection, command);
			}
			return result;
		}

		#endregion

		#region ExecuteScalar

		/// <summary>
		/// 执行返回单一值的查询。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>查询结果。</returns>
		public object ExecuteScalar(string sql)
		{
			return this.ExecuteScalar(sql, CommandType.Text, null);
		}

		/// <summary>
		/// 执行返回单一值得查询
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>查询结果。</returns>
		public virtual object ExecuteScalar(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			var connection = GetConnection();
			var command = connection.CreateCommand();
			var logger = new Logger(true);
			object result = null;
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			try
			{
				//如果开启事务，则由上层调用者决定何时提交事务
				result = command.ExecuteScalar();
			}
			catch(Exception ex)
			{
				ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				long lastElapsedTime;
				logger.Log(command, "Flagwind.Data", out lastElapsedTime);
				this.LastElapsedTime = lastElapsedTime;
				this.CloseConnection(connection, command);
			}
			return result;
		}

		#endregion

		#region ExecuteDataReader

		/// <summary>
		/// 返回单一行的数据阅读器。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReaderWithSingleRow(string sql)
		{
			IDataParameter[] paras =
			{
			};
			//在有事务的时候不能关闭连接
			return this.ExecuteDataReaderWithSingleRow(sql, paras);
		}

		/// <summary>
		/// 返回单一行的数据阅读器。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="parameters">参数。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReaderWithSingleRow(string sql, IDataParameter[] parameters)
		{
			//在有事务或者有连接会话的时候不能关闭连接
			if(this._transCount > 0 || this._sessionConnection != null)
			{
				return this.ExecuteDataReader(ref sql, CommandType.Text, CommandBehavior.SingleRow, ref parameters);
			}
			else
			{
				return this.ExecuteDataReader(ref sql, CommandType.Text, CommandBehavior.SingleRow | CommandBehavior.CloseConnection, ref parameters);
			}
		}

		/// <summary>
		/// 根据查询返回数据阅读器对象，在非事务过程中，阅读完以后会自动关闭数据库连接。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReader(string sql)
		{
			IDataParameter[] parameters =
			{
			};
			//在有事务或者有会话的时候不能关闭连接
			var behavior = this._transCount > 0 || this._sessionConnection != null ? CommandBehavior.SingleResult : CommandBehavior.SingleResult | CommandBehavior.CloseConnection;
			return this.ExecuteDataReader(ref sql, CommandType.Text, behavior, ref parameters);
		}

		/// <summary>
		/// 根据查询返回数据阅读器对象
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="behavior">对查询和返回结果有影响的说明。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReader(string sql, CommandBehavior behavior)
		{
			IDataParameter[] parameters =
			{
			};
			return this.ExecuteDataReader(ref sql, CommandType.Text, behavior, ref parameters);
		}

		/// <summary>
		/// 根据查询返回数据阅读器对象，但不可随机读取行内数据。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReader(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			//在有事务或者有会话的时候不能关闭连接。
			var behavior = this._transCount > 0 || this._sessionConnection != null ? CommandBehavior.SingleResult : CommandBehavior.SingleResult | CommandBehavior.CloseConnection;
			return this.ExecuteDataReader(ref sql, commandType, behavior, ref parameters);
		}

		/// <summary>
		/// 根据查询返回数据阅读器对象,可以顺序读取行内的大数据列。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>数据阅读器。</returns>
		public IDataReader ExecuteDataReaderSequentialAccess(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			var behavior = this._transCount == 0 ? CommandBehavior.SingleResult | CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SingleResult | CommandBehavior.SequentialAccess;
			return this.ExecuteDataReader(ref sql, commandType, behavior, ref parameters);
		}

		/// <summary>
		/// 根据查询返回数据阅读器对象。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="behavior">对查询和返回结果有影响的说明。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>数据阅读器。</returns>
		public virtual IDataReader ExecuteDataReader(ref string sql, CommandType commandType, CommandBehavior behavior, ref IDataParameter[] parameters)
		{
			var connection = GetConnection();
			var command = connection.CreateCommand();
			var logger = new Logger(true);
			IDataReader reader = null;
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			try
			{
				//如果命令对象的事务对象为空，那么强制在读取完数据后关闭阅读器的数据库连接
				if(command.Transaction == null && behavior == CommandBehavior.Default)
				{
					behavior = CommandBehavior.CloseConnection;
				}
				reader = command.ExecuteReader(behavior);
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				//只有出现了错误而且没有开启事务，可以关闭连结
				this.CloseConnection(connection, command);
				bool inTransaction = command.Transaction != null;
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			long lastElapsedTime;
			logger.Log(command, "Flagwind.Data", out lastElapsedTime);
			this.LastElapsedTime = lastElapsedTime;
			command.Parameters.Clear();
			return reader;
		}

		#endregion

		#region ExecuteInsertQuery

		/// <summary>
		/// 执行插入数据的查询。
		/// </summary>
		/// <param name="sql">插入数据的SQL。</param>
		/// <param name="id">要传出的本次操作的新插入数据行的主键ID值。</param>
		/// <returns>本次查询受影响的行数。</returns>
		public int ExecuteInsertQuery(string sql, ref object id)
		{
			return ExecuteInsertQuery(sql, CommandType.Text, null, ref id);
		}

		/// <summary>
		/// 执行插入数据的查询。
		/// </summary>
		/// <param name="sql">插入数据的SQL。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <param name="id">要传出的本次操作的新插入数据行的自增主键ID值，如果没有获取到，则为-1。</param>
		/// <returns>本次查询受影响的行数。</returns>
		public virtual int ExecuteInsertQuery(string sql, CommandType commandType, IDataParameter[] parameters, ref object id)
		{
			var connection = GetConnection();
			//连接已经打开，不能切换连接字符串。
			if(connection.State != ConnectionState.Open)
			{
				connection.ConnectionString = this.DataWriteConnectionString;
			}
			var logger = new Logger(true);
			var command = connection.CreateCommand();
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			bool inner = false;
			int result = -1;
			id = 0;
			try
			{
				if(command.Transaction == null)
				{
					inner = true;
					command.Transaction = connection.BeginTransaction();
				}
				result = command.ExecuteNonQuery();
				if(!string.IsNullOrEmpty(this.SelectIdentityText))
				{
					//不清除参数对象在Oracle会发生错误
					//但是清除了参数，会让SQL日志没法记录参数信息，故下面创建一个新的命令对象
					var cmd = connection.CreateCommand();
					cmd.CommandText = this.SelectIdentityText;
					cmd.Transaction = command.Transaction;
					id = cmd.ExecuteScalar();
				}
				else
				{
					id = -1; //表示未获取到自增列的值
				}
				//如果在内部开启了事务则提交事务，否则外部调用者决定何时提交事务
				if(inner)
				{
					command.Transaction.Commit();
					command.Transaction = null;
				}
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				if(command.Transaction != null)
				{
					command.Transaction.Rollback();
				}
				if(inner)
				{
					command.Transaction = null;
				}
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				long lastElapsedTime;
				logger.Log(command, "Flagwind.Data", out lastElapsedTime);
				this.LastElapsedTime = lastElapsedTime;
				this.CloseConnection(connection, command);
			}
			return result;
		}

		#endregion

		#region ExecuteDataSet

		/// <summary>
		/// 执行返回数据集的查询。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>数据集。</returns>
		public virtual DataSet ExecuteDataSet(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			return ExecuteDataSetWithSchema(sql, commandType, parameters, new DataSet());
		}

		/// <summary>
		/// 执行返回数据架构的查询。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		/// <returns>数据架构。</returns>
		public virtual DataSet ExecuteDataSetSchema(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			var connection = this.GetConnection();
			var command = connection.CreateCommand();
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			var adapter = this.GetDataAdapter(command);
			var result = new DataSet();
			try
			{
				adapter.FillSchema(result, SchemaType.Mapped);
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				Logger.Default.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				this.CloseConnection(connection, command);
			}
			return result;
		}

		/// <summary>
		/// 执行查询,并返回具有数据架构的数据集(整个过程仅使用一次连接)。
		/// </summary>
		/// <param name="sql">SQL 语句</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">查询参数。</param>
		/// <returns>具有数据架构的数据集。</returns>
		public virtual DataSet ExecuteDataSetWithSchema(string sql, CommandType commandType, IDataParameter[] parameters)
		{
			var connection = GetConnection();
			var command = connection.CreateCommand();
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			var adapter = GetDataAdapter(command);
			var logger = new Logger(true);
			var result = new DataSet();
			try
			{
				adapter.FillSchema(result, SchemaType.Mapped);
				adapter.Fill(result);
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				this.CloseConnection(connection, command);
			}
			long lastElapsedTime;
			logger.Log(command, "Flagwind.Data", out lastElapsedTime);
			this.LastElapsedTime = lastElapsedTime;
			return result;
		}

		/// <summary>
		/// 执行查询,并以指定的(具有数据架构的)数据集来填充数据。
		/// </summary>
		/// <param name="sql">查询语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">查询参数。</param>
		/// <param name="schemaDataSet">指定的(具有数据架构的)数据集。</param>
		/// <returns>具有数据的数据集。</returns>
		public virtual DataSet ExecuteDataSetWithSchema(string sql, CommandType commandType, IDataParameter[] parameters, DataSet schemaDataSet)
		{
			var connection = GetConnection();
			var command = connection.CreateCommand();
			this.ImproveCommand(command, ref sql, ref commandType, ref parameters);
			var adapter = GetDataAdapter(command);
			var logger = new Logger(true);
			try
			{
				adapter.Fill(schemaDataSet);
			}
			catch(Exception ex)
			{
				this.ErrorMessage = ex.Message;
				bool inTransaction = command.Transaction != null;
				logger.Error(command, "Flagwind.Data:" + ErrorMessage);
				if(OnErrorThrow)
				{
					throw new QueryException(ex.Message, command.CommandText, commandType, parameters, inTransaction, connection.ConnectionString);
				}
			}
			finally
			{
				long lastElapsedTime;
				logger.Log(command, "Flagwind.Data", out lastElapsedTime);
				this.LastElapsedTime = lastElapsedTime;
				this.CloseConnection(connection, command);
			}
			return schemaDataSet;
		}

		/// <summary>
		/// 执行返回数据集的查询。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>数据集。</returns>
		public DataSet ExecuteDataSet(string sql)
		{
			return ExecuteDataSet(sql, CommandType.Text, null);
		}

		#endregion

		#endregion

		#region 事务处理

		/// <summary>
		/// 打开连接并开启事务
		/// </summary>
		public void BeginTransaction()
		{
			this.BeginTransaction(IsolationLevel.ReadCommitted);
		}

		/// <summary>
		/// 开启事务并指定事务隔离级别
		/// </summary>
		/// <param name="level"></param>
		public void BeginTransaction(IsolationLevel level)
		{
			this._transCount++;
			this.ErrorMessage = "";
			this._connection = GetConnection(); //在子类中将会获取连接对象实例
			if(this._connection.State != ConnectionState.Open)
			{
				this._connection.Open();
			}
			if(this._transCount == 1)
			{
				this._transation = _connection.BeginTransaction(level);
			}
		}

		/// <summary>
		/// 提交事务并关闭连接
		/// </summary>
		public void Commit()
		{
			this._transCount--;
			if(this._transation != null && this._transation.Connection != null && this._transCount == 0)
			{
				this._transation.Commit();
			}
			if(this._transCount <= 0)
			{
				this.CloseGlobalConnection();
				this._transCount = 0;
			}
		}

		/// <summary>
		/// 回滚事务并关闭连接
		/// </summary>
		public void Rollback()
		{
			this._transCount--;
			if(this._transation != null && this._transation.Connection != null)
			{
				this._transation.Rollback();
			}
			this.CloseGlobalConnection();
		}

		#endregion

		#region SQL 处理

		/// <summary>
		/// 对 SQL 语句进行其它的处理，例如将 SqlServer 的字段名外的中括号替换成数据库特定的字符。
		/// 该方法会在执行查询前调用。
		/// </summary>
		/// <param name="sql">SQL 语句。</param>
		/// <returns>处理后的 SQL 语句。</returns>
		public virtual string PrepareSQL(string sql)
		{
			return sql;
		}

		#endregion

		#region 抽象方法

		/// <summary>
		/// 获取数据适配器实例。
		/// </summary>
		/// <returns>数据适配器。</returns>
		public abstract IDbDataAdapter GetDataAdapter(IDbCommand command);

		/// <summary>
		/// 获取当前数据库类型的参数数据类型名称。
		/// </summary>
		/// <param name="parameter"></param>
		/// <returns></returns>
		public abstract string GetNativeDbTypeName(IDataParameter parameter);

		#endregion

		#region 命令完善

		/// <summary>
		/// 完善命令对象,处理命令对象关联的事务和连接，如果未打开连接这里将打开它。
		/// </summary>
		/// <param name="command">命令对象。</param>
		/// <param name="sql">SQL 语句。</param>
		/// <param name="commandType">命令类型。</param>
		/// <param name="parameters">参数数组。</param>
		protected void ImproveCommand(IDbCommand command, ref string sql, ref CommandType commandType, ref IDataParameter[] parameters)
		{
			command.CommandText = SqlServerCompatible ? this.PrepareSQL(sql) : sql;
			command.CommandType = commandType;
			command.Transaction = this.Transaction;
			if(this.CommandTimeOut > 0)
			{
				command.CommandTimeout = this.CommandTimeOut;
			}
			if(parameters != null)
			{
				foreach(IDataParameter parameter in parameters)
				{
					if(parameter != null)
					{
						if(commandType != CommandType.StoredProcedure)
						{
							if(parameter.Value == null)
							{
								parameter.Value = DBNull.Value;
							}
							command.Parameters.Add(parameter);
						}
						else
						{
							//为存储过程带回返回值
							command.Parameters.Add(parameter);
						}
					}
				}
			}
			if(command.Connection.State != ConnectionState.Open)
			{
				command.Connection.Open();
			}
		}

		#endregion

		#region 会话处理

		/// <summary>
		/// 打开一个数据库连接会话，你可以在其中执行一系列查询
		/// </summary>
		/// <returns>连接会话对象</returns>
		public ConnectionSession OpenSession()
		{
			this.ErrorMessage = string.Empty;
			_sessionConnection = this.GetConnection(); //在子类中将会获取连接对象实例
			if(_sessionConnection.State != ConnectionState.Open)
			{
				_sessionConnection.Open();
			}
			return new ConnectionSession(_sessionConnection);
		}

		/// <summary>
		/// 关闭连接会话
		/// </summary>
		public void CloseSession()
		{
			if(_sessionConnection != null && _sessionConnection.State == ConnectionState.Open)
			{
				_sessionConnection.Close();
				_sessionConnection.Dispose();
				_sessionConnection = null;
			}
		}

		/// <summary>
		/// 关闭连接。
		/// </summary>
		/// <param name="connection">连接对象。</param>
		/// <param name="command">命令对象。</param>
		protected void CloseConnection(IDbConnection connection, IDbCommand command)
		{
			if(command.Transaction == null && connection != _sessionConnection && connection.State == ConnectionState.Open)
			{
				connection.Close();
			}
			command.Parameters.Clear();
		}

		private void CloseGlobalConnection()
		{
			if(_connection != null && _connection.State == ConnectionState.Open)
			{
				_connection.Close();
			}
		}

		#endregion

		#region 资源释放

		void IDisposable.Dispose()
		{
			if(!this._disposed)
			{
				this.Dispose(true);
				this._disposed = true;
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			if(disposing)
			{
				this.CloseGlobalConnection();
				this.CloseSession();
			}
			this._connection = null;
			this._transation = null;
			this._sessionConnection = null;
		}

		#endregion
	}
}